To access the M360 Customer API you have to first activate it by logging in to your dashboard and setting the API status to Testing or Live. If you wish to disable your API access later, you can set the API status on your dashboard to Disabled. To enable and use your M360 Customer API account you will need a valid and active M360 licence.
Calling any API endpoint in Testing mode will never cause any data changes. Also, responses in this mode will be randomly generated but syntactically correct data structures. You can use this mode to safely experiment with the M360 Customer API and test your integration. Once you have tested your system and feel confident you can switch to Live mode.
Most endpoints can be called in testing mode even if your API is live, by providing the optional testing request parameter and setting its value to true. This will result in exactly the same behaviour and response as if your API was in Testing mode.
To call any M360 Customer API endpoint just issue an HTTP POST request with an application/json content type to the URL of the endpoint. The body of the request should be a simple JSON object containing the input parameters shown at the endpoint's documentation.
With every /v2 API request you must provide the correct authentication information which is different from your M360 login username and password. You need to use an Authorization header, with a bearer token. Your bearer token is simply your authCode and authToken, concatenated with a - (dash) character:
POST https://m360soft.com/api/customer/v2/getHistory
User-Agent: curl/7.54.1
Authorization: Bearer a167b9ae-948d-490c-9995-932984fbb223-f3e1016b87d4d11d7994d39050ac5d05ef475bc422131b0916337f0c0a424be3
{
"limit": 100
}
The authCode parameter is the unique identifier of your M360 Customer API account and the authToken is the secret key of it. You can access both of them on your dashboard at the API information section. For safety reasons the authToken can only be viewed or regenerated after providing your M360 password (the one you use to log in to your dashboard).
Every M360 Customer API response will be a JSON object containing two properties: data and meta.
The data object will be populated with the specific information that the called API endpoint provides, so its structure and content varies between endpoints. For example a successful but empty /v2/getHistory response will be like this:
{
"data": {
"records": [],
"hasMore": false
},
"meta": {
"success": true
}
}
The meta object has a more rigid structure and always contains the boolean status property success, and in case of any error the errors object. The errors object has 3 properties: code, title and details. The code is the ID of the error, while the title is a human-readable description of it. If you would like to handle specific errors, always build your logic on the code error property instead of the title.
Example error response:
{
"data": [],
"meta": {
"success": false,
"errors": {
"code": "auth:forbidden",
"title": "Access forbidden with the given credentials",
"details": []
}
}
}
There is a limit on the number of requests you can make to any Customer API endpoints, which is based on your active licences and upgrades. You can make 1 request / second / workstations. So if you have a Professional Licence with 2 additional workstation upgrades then you are limited to a total of 5 requests / second. If you encounter a rate limit error, you will receive a 429 Too Many Requests HTTP status code, and a JSON error response containing the effective rate limit of your account:
{
"data": [],
"meta": {
"success": false,
"errors": {
"code": "customer_api:too_many_requests",
"title": "Too many requests",
"details": {
"maximumRequestsPerSecond": 5
}
}
}
}
The M360 Customer API is a versioned API. The current version is v2. We will support the previous versions for a reasonable time, but we encourage you to always use the latest version of the API. We will announce the deprecation of a version at least 6 months before the end of support.
We introduce new versions of the API when we make breaking changes to the existing endpoints or the API in general. Between versions, we may introduce non-breaking changes, such as new endpoints or new properties in the response objects. We will document these changes in the changelog.
A breaking change is a change that can cause existing integrations to stop working and may require changes to the client code.
Examples of breaking changes include:
A non-breaking change is a change that does not require changes to the client code.
Examples of non-breaking changes include:
Migrating from the v1 to the v2 version of the M360 Customer API should be straightforward, but there are some major changes you need to be aware of.
The v2 API uses a different authentication method. You need to use an Authorization header with a bearer token instead of the authCode and authToken request parameters. The bearer token is simply your authCode and authToken, concatenated with a - (dash) character.
The /getHistory endpoint has been significantly changed, both in the request and response structure.
Input parameters:
imei filter accepted a serial number too. In the v2 API, there is a separate serial filter for this purpose. The imei filter now only accepts IMEI numbers.imei filter is now an array instead of a single string. You can provide and search for multiple IMEI numbers in a single request.m360id filter is now an array instead of a single string. You can provide and search for multiple M360 IDs in a single request.customId filter which allows you to search for devices using the custom ID you have saved as sticky data for the device.marketingName filter was renamed to friendlyName to reflect the name change of the relevant property in the response object.timeZone parameter to get the timestamps in the response in the specified time zone. The default is UTC.calculateTotalCount parameter which allows you to request the calculation of the number of matching rows. The default value is false.Response data:
totalCount property is not populated in the response object by default. You can use the hasMore property to check if there are more records available or if you need this value you can set the calculateTotalCount request parameter to true. But keep in mind that even if you request the calculation of the number of matching rows, the total count will never be more than 10000. If you have more records, please use filtering to get a smaller result set.DeviceSession object:
marketingName and alternativeMarketingNames properties were renamed to friendlyName and alternativeFriendlyNames respectively in the response object. However, there is a new marketingName property, which is different from the friendlyName. The marketingName property contains the original marketing name of the device, without color or storage size information. At the moment this value is only available for Apple devices.imei1 property was renamed to imei.imei3 property was removed.batteryHealth property was removed.historicalStickyData property was renamed to stickyData.blacklistChecks property was removed. Instead of this, there is a new blacklistCheckResult property which contains the result of the last IMEI blacklist check at the time of the session.reports property was renamed to diagnosticsReports.brandAccounts, simLock, soc, brand, ecid, internalStorage, iosSalesRegion, MDMState, batteryCycles, batteryDesignCapacity, fullChargeCapacity, rooted, secureLocked, memoryCard, iosRegulatoryModel, deviceColor, iosJailbreak, encryptionState, encryptionType, deviceExpense, gradingPhotos, simLockCheckResult.Device object:
id property was removed. Instead you can use the m360id property to identify the device.actualGradingResult, actualGradingPhotos, actualDeviceExpense.StickyData object:
customerInfo property was removed.customerInfo there is a new client property. The client object is either a Company or a Person object, depending on the type of the client. You can use the type property to determine the type of the client.DiagnosticsResult object:
clientTime property was renamed to finishTime.tests property which contains the test results in an array.DiagnosticsResultTest object:
testId property now holds the ID of the test, instead of the former approach where the test ID was the key of the object.result property is similar to the former status property, but the possible values are different. The new possible values NA, Passed, Failed, and Skipped.details property is a list of DiagnosticsResultDetail objects, which hold details of test results.DiagnosticsResultDetail object:
The purpose of this new object is similar to the details property of the TestResult object of the v1 API, but its structure is different. It holds a single, additional detail of a diagnostics test. For example the battery test can provide details about the original capacity of the battery, temperature, voltage, etc. In the v1 API these were all different keys of the details object, now these are provided as individual details objects. For example:
v1 API:
"batteryHealth": {
"status": "passed",
"details": {
"cycles": "254",
"designCapacityCapacity": "4395 mAh"
}
}
v2 API:
{
"testId": "Battery",
"result": "Passed",
"details": [
{
"context": "BatteryOriginalCapacity",
"title": "Original Capacity",
"result": "NA"
"value": "4395 mAh"
},
{
"context": "BatteryCycles",
"title": "Battery Cycles",
"result": "NA"
"value": "254"
}
]
}
| Test | Old key | New context ID |
|---|---|---|
| Battery | temperature | BatteryTemperature |
| Battery | voltage | BatteryVoltage |
| Battery | technology | BatteryTechnology |
| Battery | designCapacity | BatteryOriginalCapacity |
| Battery | fullCapacity | BatteryCurrentCapacity |
| Battery | cycles | BatteryCycles |
| Battery | batteryDrainPercent | BatteryDrainPercentLost |
| Storage | total | StorageTotal |
| Storage | free | StorageFree |
| Storage | used | StorageUsed |
OemCheckResult object:
isAuthentic flag that tells whether the device is authentic or not.result. id property of the OemCheckResultPart object to identify the part, instead of the old method of using the key of the object.name property was added to the object to provide a human-readable name of the part.GradingResult object:
clientTime property was renamed to modificationTimestamp.case property was renamed to phoneCase.cover property was renamed to back.BlacklistCheckResult object:
status property was removed.